/**
 * 
 */
package org.swing.utility.common.clazz;

import java.io.File;
import java.io.FileInputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.lang.reflect.ParameterizedType;

import org.apache.commons.collections15.CollectionUtils;
import org.apache.commons.lang.ClassUtils;
import org.apache.log4j.Logger;
import org.swing.utility.common.file.FileUtil;
import org.swing.utility.common.reflect.ReflectUtil;

/**
 * @author lqnhu
 *
 */
public class ClassUtil {

	private static final Logger LOG = Logger.getLogger(ClassUtil.class);
	private static final Map<Class<?>, List<Class<?>>> CACHE_getSuperClasses = new HashMap<Class<?>, List<Class<?>>>();
	private static final Map<Class<?>, Set<Class<?>>> CACHE_getInterfaceClasses = new HashMap<Class<?>, Set<Class<?>>>();

	/**
	 * @param clazz
	 * @return
	 */
	public static <T> Field[] getFieldsByType(Class<?> clazz,
			Class<? extends T> fieldType) {
		List<Field> fields = new ArrayList<Field>();
		for (Field f : clazz.getDeclaredFields()) {
			int modifiers = f.getModifiers();
			if (Modifier.isTransient(modifiers) == false
					&& Modifier.isPublic(modifiers) == true
					&& Modifier.isStatic(modifiers) == false
					&& ClassUtil.getSuperClasses(f.getType()).contains(
							fieldType)) {
				fields.add(f);
			}
		} // FOR
		return (fields.toArray(new Field[fields.size()]));
	}

	/**
	 * Returns true if asserts are enabled. This assumes that we're always using
	 * the default system ClassLoader
	 */
	public static boolean isAssertsEnabled() {
		boolean ret = false;
		try {
			assert (false);
		} catch (AssertionError ex) {
			ret = true;
		}
		return (ret);
	}

	/**
	 * Convenience method to get the name of the method that invoked this method
	 * This is slow and should not be used for anything other than debugging
	 * 
	 * @return
	 */
	public static String getCurrentMethodName() {
		StackTraceElement stack[] = Thread.currentThread().getStackTrace();
		assert (stack[2] != null);
		return String.format("%s.%s", stack[2].getClassName(),
				stack[2].getMethodName());
	}

	/**
	 * Return the stack trace for the location that calls this method.
	 * 
	 * @return
	 */
	public static String[] getStackTrace() {
		String ret[] = null;
		try {
			throw new Exception();
		} catch (Exception ex) {
			StackTraceElement stack[] = ex.getStackTrace();
			ret = new String[stack.length - 1];
			for (int i = 1; i < stack.length; i++) {
				ret[i - 1] = stack[i].toString();
			} // FOR
		}
		return (ret);
	}

	/**
	 * Check if the given object is an array (primitve or native).
	 * http://www.java2s .com/Code/Java/Reflection/
	 * Checkifthegivenobjectisanarrayprimitveornative .htm
	 *
	 * @param obj
	 *            Object to test.
	 * @return True of the object is an array.
	 */
	public static boolean isArray(final Object obj) {
		return (obj != null ? obj.getClass().isArray() : false);
	}

	public static boolean[] isArray(final Object objs[]) {
		boolean is_array[] = new boolean[objs.length];
		for (int i = 0; i < objs.length; i++) {
			is_array[i] = ClassUtil.isArray(objs[i]);
		} // FOR
		return (is_array);
	}

	/**
	 * Convert a Enum array to a Field array This assumes that the name of each
	 * Enum element corresponds to a data member in the clas
	 *
	 * @param <E>
	 * @param clazz
	 * @param members
	 * @return
	 * @throws NoSuchFieldException
	 */
	public static <E extends Enum<?>> Field[] getFieldsFromMembersEnum(
			Class<?> clazz, E members[]) throws NoSuchFieldException {
		Field fields[] = new Field[members.length];
		for (int i = 0; i < members.length; i++) {
			fields[i] = clazz.getDeclaredField(members[i].name().toLowerCase());
		} // FOR
		return (fields);
	}

	/**
	 * Create a mapping from Field handles to their corresponding Annotation
	 * 
	 * @param <A>
	 * @param fields
	 * @param annotationClass
	 * @return
	 */
	public static <A extends Annotation> Map<Field, A> getFieldAnnotations(
			Field fields[], Class<A> annotationClass) {
		Map<Field, A> ret = new LinkedHashMap<Field, A>();
		for (Field f : fields) {
			A a = f.getAnnotation(annotationClass);
			if (a != null)
				ret.put(f, a);
		}
		return (ret);
	}

	/**
	 * Get the generic types for the given field
	 *
	 * @param field
	 * @return
	 */
	public static List<Class<?>> getGenericTypes(Field field) {
		ArrayList<Class<?>> generic_classes = new ArrayList<Class<?>>();
		Type gtype = field.getGenericType();
		if (gtype instanceof ParameterizedType) {
			ParameterizedType ptype = (ParameterizedType) gtype;
			getGenericTypesImpl(ptype, generic_classes);
		}
		return (generic_classes);
	}

	private static void getGenericTypesImpl(ParameterizedType ptype,
			List<Class<?>> classes) {
		// list the actual type arguments
		for (Type t : ptype.getActualTypeArguments()) {
			if (t instanceof Class<?>) {
				// System.err.println("C: " + t);
				classes.add((Class<?>) t);
			} else if (t instanceof ParameterizedType) {
				ParameterizedType next = (ParameterizedType) t;
				// System.err.println("PT: " + next);
				classes.add((Class<?>) next.getRawType());
				getGenericTypesImpl(next, classes);
			}
		} // FOR
		return;
	}

	/**
	 * Return an ordered list of all the sub-classes for a given class Useful
	 * when dealing with generics
	 *
	 * @param element_class
	 * @return
	 */
	public static List<Class<?>> getSuperClasses(Class<?> element_class) {
		List<Class<?>> ret = ClassUtil.CACHE_getSuperClasses.get(element_class);
		if (ret == null) {
			ret = new ArrayList<Class<?>>();
			while (element_class != null) {
				ret.add(element_class);
				element_class = element_class.getSuperclass();
			} // WHILE
			ret = Collections.unmodifiableList(ret);
			ClassUtil.CACHE_getSuperClasses.put(element_class, ret);
		}
		return (ret);
	}

	/**
	 * Get a set of all of the interfaces that the element_class implements
	 *
	 * @param element_class
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static Collection<Class<?>> getInterfaces(Class<?> element_class) {
		Set<Class<?>> ret = ClassUtil.CACHE_getInterfaceClasses
				.get(element_class);
		if (ret == null) {
			// ret = new HashSet<Class<?>>();
			// Queue<Class<?>> queue = new LinkedList<Class<?>>();
			// queue.add(element_class);
			// while (!queue.isEmpty()) {
			// Class<?> current = queue.poll();
			// for (Class<?> i : current.getInterfaces()) {
			// ret.add(i);
			// queue.add(i);
			// } // FOR
			// } // WHILE
			ret = new HashSet<Class<?>>(
					ClassUtils.getAllInterfaces(element_class));
			if (element_class.isInterface())
				ret.add(element_class);
			ret = Collections.unmodifiableSet(ret);
			ClassUtil.CACHE_getInterfaceClasses.put(element_class, ret);
		}
		return (ret);
	}

	@SuppressWarnings("unchecked")
	public static <T> T newInstance(String class_name, Object params[],
			Class<?> classes[]) {
		return ((T) ClassUtil.newInstance(ClassUtil.getClass(class_name),
				params, classes));
	}

	public static <T> T newInstance(Class<T> target_class, Object params[],
			Class<?> classes[]) {
		// Class<?> const_params[] = new Class<?>[params.length];
		// for (int i = 0; i < params.length; i++) {
		// const_params[i] = params[i].getClass();
		// System.err.println("[" + i + "] " + params[i] + " " +
		// params[i].getClass());
		// } // FOR
		Constructor<T> constructor = ClassUtil.getConstructor(target_class,
				classes);
		T ret = null;
		try {
			ret = constructor.newInstance(params);
		} catch (Exception ex) {
			throw new RuntimeException("Failed to create new instance of "
					+ target_class.getSimpleName(), ex);
		}
		return (ret);
	}

	/**
	 * Grab the constructor for the given target class with the provided input
	 * parameters. This method will first try to find an exact match for the
	 * parameters, and if that fails then it will be smart and try to find one
	 * with the input parameters super classes.
	 * 
	 * @param <T>
	 * @param target_class
	 * @param params
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> Constructor<T> getConstructor(Class<T> target_class,
			Class<?>... params) {
		NoSuchMethodException error = null;
		try {
			return (target_class.getConstructor(params));
		} catch (NoSuchMethodException ex) {
			// The first time we get this it can be ignored
			// We'll try to be nice and find a match for them
			error = ex;
		}
		assert (error != null);
		final int num_params = (params != null ? params.length : 0);
		List<Class<?>> paramSuper[] = (List<Class<?>>[]) new List[num_params];
		for (int i = 0; i < num_params; i++) {
			paramSuper[i] = ClassUtil.getSuperClasses(params[i]);
		} // FOR

		for (Constructor<?> c : target_class.getConstructors()) {
			Class<?> cTypes[] = c.getParameterTypes();
			if (params.length != cTypes.length)
				continue;
			for (int i = 0; i < num_params; i++) {
				List<Class<?>> cSuper = ClassUtil.getSuperClasses(cTypes[i]);
				if (CollectionUtils.intersection(paramSuper[i], cSuper)
						.isEmpty() == false) {
					return ((Constructor<T>) c);
				}
			} // FOR (param)
		} // FOR (constructors)
		throw new RuntimeException("Failed to retrieve constructor for "
				+ target_class.getSimpleName(), error);
	}

	/**
	 * @param class_name
	 * @return
	 */
	public static Class<?> getClass(String class_name) {
		Class<?> target_class = null;
		try {
			ClassLoader loader = ClassLoader.getSystemClassLoader();
			target_class = (Class<?>) loader.loadClass(class_name);
		} catch (Exception ex) {
			throw new RuntimeException("Failed to retrieve class for "
					+ class_name, ex);
		}
		return (target_class);
	}

	/**
	 * Finds an instance of an Enum constant on a class. Useful for safely
	 * getting the value of an enum constant without an exception being thrown
	 * like the Enum.valueOf() method causes. Searches for enum constant where
	 * case is sensitive.
	 */
	public static Object findEnumConstant(Class<?> type, String constantName) {
		return findEnumConstant(type, constantName, true);
	}

	/**
	 * Finds an instance of an Enum constant on a class. Useful for safely
	 * getting the value of an enum constant without an exception being thrown
	 * like the Enum.valueOf() method causes. Also, this method optionally
	 * allows the caller to choose whether case matters during the search.
	 */
	public static Object findEnumConstant(Class<?> type, String constantName,
			boolean caseSensitive) {
		if (!type.isEnum()) {
			return null;
		}
		for (Object obj : type.getEnumConstants()) {
			String name = obj.toString();
			if ((caseSensitive && name.equals(constantName))
					|| (!caseSensitive && name.equalsIgnoreCase(constantName))) {
				return obj;
			}
		}
		// otherwise, it wasn't found
		return null;
	}

	/**
	 * Returns an array of class objects representing the entire class hierarchy
	 * with the most-super class as the first element followed by all subclasses
	 * in the order they are declared. This method does not include the generic
	 * Object type in its list. If this class represents the Object type, this
	 * method will return a zero-size array.
	 */
	public static Class<?>[] getClassHierarchy(Class<?> type) {
		ArrayDeque<Class<?>> classes = new ArrayDeque<Class<?>>();
		// class to start our search from, we'll loop thru the entire class
		// hierarchy
		Class<?> classType = type;
		// keep searching up until we reach an Object class type
		while (classType != null && !classType.equals(Object.class)) {
			// keep adding onto front
			classes.addFirst(classType);
			classType = classType.getSuperclass();
		}
		return classes.toArray(new Class[0]);
	}

	/**
	 * Checks if the class implements public "bean" methods (get and set) for
	 * the name. For example, for a name such as "firstName", this method will
	 * check if the class has both getFirstName() and setFirstName() methods.
	 * Also, this method will validate the return type matches the paramType on
	 * the getXXX() method and that the setXXX() method only accepts that
	 * paramType. The search is optionally case sensitive.
	 * 
	 * @param type
	 *            The class to search
	 * @param propertyName
	 *            The property name to search for, if "firstName", then this
	 *            method will internally add the "get" and "set" to the
	 *            beginning.
	 * @param propertyType
	 *            The class type of the property
	 * @param caseSensitive
	 *            If the search is case sensitive or not
	 * @return True if the "bean" methods are correct, otherwise false.
	 */
	public static boolean hasBeanMethods(Class<?> type, String propertyName,
			Class<?> propertyType, boolean caseSensitive) {
		try {
			// if this succeeds without an exception, then the properties exist!
			@SuppressWarnings("unused")
			Method[] methods = getBeanMethods(type, propertyName, propertyType,
					caseSensitive);
			return true;
		} catch (Exception e) {
			return false;
		}
	}

	/**
	 * Gets the methods within this class that implements public "bean" methods
	 * (get and set) for the property name. Returns an array of methods where
	 * index=0 is the get method and index=1 is the set method. For example, for
	 * a name such as "firstName", this method will check if the class has both
	 * getFirstName() and setFirstName() methods. Also, this method will
	 * validate the return type matches the propertyType on the getXXX() method
	 * and that the setXXX() method only accepts that propertyType. The search
	 * is optionally case sensitive.
	 * 
	 * @param type
	 *            The class to search
	 * @param propertyName
	 *            The name to search for
	 * @param paramType
	 *            The class type of the property
	 * @param caseSensitive
	 *            If the search is case sensitive or not
	 * @return An array of Methods were index=0 is the get method and index=1 is
	 *         the set method
	 * @throws java.lang.IllegalAccessException
	 *             If the method was found, but is not public.
	 * @throws java.lang.NoSuchMethodException
	 *             If the method was not found
	 */
	public static Method[] getBeanMethods(Class<?> type, String propertyName,
			Class<?> propertyType, boolean caseSensitive)
			throws IllegalAccessException, NoSuchMethodException {
		Method methods[] = new Method[2];
		// search for the "get"
		methods[0] = getMethod(type, "get" + propertyName, propertyType, null,
				caseSensitive);
		// search for the "set"
		methods[1] = getMethod(type, "set" + propertyName, null, propertyType,
				caseSensitive);
		return methods;
	}

	/**
	 * Gets the public method within the type that matches the method name,
	 * return type, and single parameter type. Optionally is a case sensitive
	 * search. Useful for searching for "bean" methods on classes.
	 * 
	 * @param type
	 *            The class to search for the method
	 * @param name
	 *            The name of the method to search for
	 * @param returnType
	 *            The expected return type or null if its expected to be a void
	 *            method
	 * @param paramType
	 *            The expected parameter type or null if no parameters are
	 *            expected
	 * @param caseSensitive
	 *            True if its a case sensitive search, otherwise false
	 * @return The method matching the search criteria
	 * @throws java.lang.IllegalAccessException
	 *             If the method was found, but is not public.
	 * @throws java.lang.NoSuchMethodException
	 *             If the method was not found
	 */
	public static Method getMethod(Class<?> type, String name,
			Class<?> returnType, Class<?> paramType, boolean caseSensitive)
			throws IllegalAccessException, NoSuchMethodException {
		// flag to help modify the exception to make it a little easier for
		// debugging
		boolean methodNameFound = false;
		// start our search
		Class<?> classType = type;
		while (classType != null && !classType.equals(Object.class)) {
			for (Method m : classType.getDeclaredMethods()) {
				if ((!caseSensitive && m.getName().equalsIgnoreCase(name))
						|| (caseSensitive && m.getName().equals(name))) {
					// we found the method name, but its possible the signature
					// won't
					// match below, we'll set this flag to help construct a
					// better exception
					// below
					methodNameFound = true;
					// should we validate the return type?
					if (returnType != null) {
						// if the return types don't match, then this must be
						// invalid
						// since the JVM doesn't allow the same return type
						if (!m.getReturnType().equals(returnType)) {
							throw new NoSuchMethodException("Method '" + name
									+ "' was found in " + type.getSimpleName()
									+ ".class" + ", but the returnType "
									+ m.getReturnType().getSimpleName()
									+ ".class did not match expected "
									+ returnType.getSimpleName() + ".class");
						}
						// make sure the return type is VOID
					} else {
						if (!m.getReturnType().equals(void.class)) {
							throw new NoSuchMethodException("Method '" + name
									+ "' was found in " + type.getSimpleName()
									+ ".class" + ", but the returnType "
									+ m.getReturnType().getSimpleName()
									+ ".class was expected to be void");
						}
					}
					// return type was okay, check the parameters
					Class<?>[] paramTypes = m.getParameterTypes();
					// should we check the parameter type?
					if (paramType != null) {
						// must have exactly 1 parameter
						if (paramTypes.length != 1) {
							// this might not be the method we want, keep
							// searching
							continue;
						} else {
							// if the parameters don't match, keep searching
							if (!paramTypes[0].equals(paramType)) {
								continue;
							}
						}
						// if paramType was null, then make sure no parameters
						// are expected
					} else {
						if (paramTypes.length != 0) {
							continue;
						}
					}
					// if we got here, then everything matches so far
					// now its time to check if the method is accessible
					if (!Modifier.isPublic(m.getModifiers())) {
						throw new IllegalAccessException("Method '" + name
								+ "' was found in " + type.getSimpleName()
								+ ".class "
								+ ", but its not accessible since its "
								+ Modifier.toString(m.getModifiers()));
					}
					// everything was okay
					return m;
				}
			}
			// move onto the superclass
			classType = classType.getSuperclass();
		}
		String signature = "public "
				+ (returnType == null ? "void" : returnType.getName()) + " "
				+ name + "(" + (paramType == null ? "" : paramType.getName())
				+ ")";
		if (methodNameFound) {
			throw new NoSuchMethodException("Method '" + signature
					+ "' was found in " + type.getSimpleName()
					+ ".class, but signature match failed");
		} else {
			throw new NoSuchMethodException("Method '" + signature
					+ "' was not found in " + type.getSimpleName() + ".class");
		}
	}

	// =============================================================================================================

	public static List<String> getClassFromClassPathAndJars(String... regex) {
		List<String> classes = getClassFromJars(regex);
		List<String> _classes = getClassFromClassPath(regex);
		classes.addAll(_classes);
		return classes;
	}

	public static List<String> getClassFromClassPath(String... regex) {
		List<String> classes = new ArrayList<String>();
		String classpath = FileUtil.getTopClassPath(ClassUtil.class).replace(
				"\\", "/");
		if (classpath.startsWith("/"))
			classpath = classpath.substring(1);
		List<File> files = getFilesFromClassPath(classpath);
		for (File f : files) {
			String n = f.getAbsolutePath().replace("\\", "/")
					.replace(classpath, "");
			String className = n.replace("/", ".").replace(".class", "");
			if (regex != null && regex.length > 0) {
				for (String rgx : regex) {
					if (className.matches(rgx)) {
						classes.add(className);
						break;
					}
				}
			} else
				classes.add(className);
		}
		return classes;
	}

	public static List<File> getFilesFromClassPath(String classpath) {
		File dir = new File(classpath);
		return getFilesFromDir(dir);
	}

	public static List<File> getFilesFromDir(File dir) {
		List<File> files = new ArrayList<File>();
		for (File f : dir.listFiles()) {
			if (!dir.exists())
				continue;
			if (f.isDirectory()) {
				List<File> _files = getFilesFromDir(f);
				files.addAll(_files);
				continue;
			}
			files.add(f);
		}
		return files;
	}

	public static List<String> getClassFromJars(String... regex) {
		List<String> classes = new ArrayList<String>();
		List<File> jars = getJars();
		for (File jar : jars) {
			List<String> _classes = getClassFromJar(jar, regex);
			classes.addAll(_classes);
		}
		return classes;
	}

	private static List<String> getClassFromJar(File jar, String... regex) {
		List<String> files = new ArrayList<String>();
		if (jar == null)
			return files;
		ZipInputStream zin = null;
		ZipEntry entry = null;
		try {
			zin = new ZipInputStream(new FileInputStream(jar));
			while ((entry = zin.getNextEntry()) != null) {
				String entryName = entry.getName().replace("\\", "/")
						.replace('/', '.');
				if (!entryName.endsWith(".class"))
					continue;
				final String className = entryName.replace(".class", "");
				if (regex != null && regex.length > 0) {
					for (String rgx : regex) {
						if (className.matches(rgx)) {
							files.add(className);
							break;
						}
					}
				} else
					files.add(className);
				zin.closeEntry();
			}
			zin.close();
		} catch (Error e) {
		} catch (Exception e) {
		}
		return files;
	}

	public static List<File> getJars(String... regex) {
		List<File> jars = new ArrayList<File>();
		List<String> paths = FileUtil.getJars();
		List<String> validPaths = _filter_jars(paths, regex);
		for (String p : validPaths) {
			File jar = new File(p);
			if (!jar.exists() || !jar.isFile())
				continue;
			jars.add(jar);
		}
		return jars;
	}

	private static List<String> _filter_jars(List<String> _jars,
			String... regex) {
		List<String> list = new ArrayList<String>();
		if (_jars == null)
			return list;
		for (String _jar : _jars) {
			String jar = _jar.replace("\\", "/");
			final String name = new File(jar).getName().replace(".jar", "");
			if (regex == null || regex.length == 0) {
				list.add(jar);
				continue;
			}
			if (!name.matches(regex[0]))
				continue;
			list.add(jar);
		}
		return list;
	}

	public static Class<?> getGenericReturnType(Method method) {
		Type type = method.getGenericReturnType();
		String clsName = type.toString();
		if (clsName.contains("<") && clsName.contains(">")) {
			int s = clsName.indexOf("<") + 1;
			int e = clsName.indexOf(">");
			String str = clsName.substring(s, e);
			return ClassUtil.getPojoClass(str);
		} else
			return method.getReturnType();
	}

	public static Class<?> getPojoClass(String className) {
		Class<?> cls;
		try {
			cls = Thread.currentThread().getContextClassLoader()
					.loadClass(className);
			if (isPojo(cls))
				return cls;
		} catch (ClassNotFoundException e) {
		}
		return null;
	}

	public static boolean isPojo(Class<?> cls) {
		if (cls == null)
			return false;
		if (Collection.class.isAssignableFrom(cls)) {
		} else {
			if (Integer.class.isAssignableFrom(cls)
					|| int.class.isAssignableFrom(cls)) {
			} else if (Integer[].class.isAssignableFrom(cls)
					|| int[].class.isAssignableFrom(cls)) {
			} else if (Long.class.isAssignableFrom(cls)
					|| long.class.isAssignableFrom(cls)) {
			} else if (Long[].class.isAssignableFrom(cls)
					|| long[].class.isAssignableFrom(cls)) {
			} else if (Float.class.isAssignableFrom(cls)
					|| float.class.isAssignableFrom(cls)) {
			} else if (Float[].class.isAssignableFrom(cls)
					|| float[].class.isAssignableFrom(cls)) {
			} else if (Double.class.isAssignableFrom(cls)
					|| double.class.isAssignableFrom(cls)) {
			} else if (Double[].class.isAssignableFrom(cls)
					|| double[].class.isAssignableFrom(cls)) {
			} else if (String.class.isAssignableFrom(cls)) {
			} else if (String[].class.isAssignableFrom(cls)) {
			} else if (Date.class.isAssignableFrom(cls)) {
			} else if (Date[].class.isAssignableFrom(cls)) {
			} else {
				try {
					cls.newInstance();
					return true;
				} catch (InstantiationException e) {
				} catch (IllegalAccessException e) {
				}
			}
		}
		return false;
	}

	public static <T> T injectFieldValue(T pojo, String fieldName, String[] vs)
			throws Exception {
		if (pojo == null)
			return null;
		if (vs == null)
			return pojo;
		ReflectUtil ru = new ReflectUtil(pojo);
		Field f = ru.getField(fieldName);
		if (f == null)
			return pojo;
		Method setter = ru.getSetter(fieldName);
		if (setter == null)
			return pojo;
		Class<?> clazz = f.getType();
		if (Object[].class.isAssignableFrom(clazz)) {
			Object obj = getParamVals(clazz, vs);
			if (obj != null)
				setter.invoke(pojo, new Object[] { obj });
		} else {
			Object obj = getParamVal(clazz, vs[0]);
			if (obj != null)
				setter.invoke(pojo, obj);
		}
		return pojo;
	}

	public static Object getParamVal(Class<?> fieldType, String fieldVal) {
		Class<?> clazz = fieldType;
		String v = fieldVal;
		if (v == null)
			return null;
		try {
			if (int.class.isAssignableFrom(clazz)
					|| Integer.class.isAssignableFrom(clazz)) {
				if ("".equals(v.trim()))
					v = "0";
				try {
					return Integer.parseInt(v);
				} catch (Exception e) {
					return 0;
				}
			} else if (long.class.isAssignableFrom(clazz)
					|| Long.class.isAssignableFrom(clazz)) {
				if ("".equals(v.trim()))
					v = "0L";
				try {
					return Long.parseLong(v);
				} catch (Exception e) {
					return 0L;
				}
			} else if (double.class.isAssignableFrom(clazz)
					|| Double.class.isAssignableFrom(clazz)) {
				if ("".equals(v.trim()))
					v = "0.0D";
				try {
					return Double.parseDouble(v);
				} catch (Exception e) {
					return 0.0D;
				}
			} else if (float.class.isAssignableFrom(clazz)
					|| Float.class.isAssignableFrom(clazz)) {
				if ("".equals(v.trim()))
					v = "0.0F";
				try {
					return Float.parseFloat(v);
				} catch (Exception e) {
					return 0.0F;
				}
			} else if (boolean.class.isAssignableFrom(clazz)
					|| Boolean.class.isAssignableFrom(clazz)) {
				if ("".equals(v.trim()))
					v = "false";
				try {
					return Boolean.parseBoolean(v);
				} catch (Exception e) {
					return false;
				}
			} else if (String.class.isAssignableFrom(clazz)) {
				return v;
			}
		} catch (Exception e) {
			e.printStackTrace();
		} catch (Error e) {
			e.printStackTrace();
		}
		return null;
	}

	public static Object getParamVals(Class<?> fieldType, String[] fieldVals) {
		Class<?> clazz = fieldType;
		String[] vs = fieldVals;
		if (vs == null)
			return null;
		try {
			int length = vs.length;
			if (Integer[].class.isAssignableFrom(clazz)) {
				Integer[] args = new Integer[length];
				for (int i = 0; i < vs.length; i++) {
					if ("".equals(vs[i].trim()))
						vs[i] = "0";
					try {
						args[i] = Integer.parseInt(vs[i]);
					} catch (Exception e) {
						args[i] = 0;
					}
				}
				return args;
			} else if (int[].class.isAssignableFrom(clazz)) {
				int[] args = new int[length];
				for (int i = 0; i < vs.length; i++) {
					if ("".equals(vs[i].trim()))
						vs[i] = "0";
					try {
						args[i] = Integer.parseInt(vs[i]);
					} catch (Exception e) {
						args[i] = 0;
					}
				}
				return args;
			} else if (Long[].class.isAssignableFrom(clazz)) {
				Long[] args = new Long[vs.length];
				for (int i = 0; i < vs.length; i++) {
					if ("".equals(vs[i].trim()))
						vs[i] = "0";
					try {
						args[i] = Long.parseLong(vs[i]);
					} catch (Exception e) {
						args[i] = 0L;
					}
				}
				return args;
			} else if (long[].class.isAssignableFrom(clazz)) {
				long[] args = new long[vs.length];
				for (int i = 0; i < vs.length; i++) {
					if ("".equals(vs[i].trim()))
						vs[i] = "0";
					try {
						args[i] = Long.parseLong(vs[i]);
					} catch (Exception e) {
						args[i] = 0L;
					}
				}
				return args;
			} else if (Double[].class.isAssignableFrom(clazz)) {
				Double[] args = new Double[vs.length];
				for (int i = 0; i < vs.length; i++) {
					if ("".equals(vs[i].trim()))
						vs[i] = "0.0";
					try {
						args[i] = Double.parseDouble(vs[i]);
					} catch (Exception e) {
						args[i] = 0.0D;
					}
				}
				return args;
			} else if (double[].class.isAssignableFrom(clazz)) {
				double[] args = new double[vs.length];
				for (int i = 0; i < vs.length; i++) {
					if ("".equals(vs[i].trim()))
						vs[i] = "0.0";
					try {
						args[i] = Double.parseDouble(vs[i]);
					} catch (Exception e) {
						args[i] = 0.0D;
					}
				}
				return args;
			} else if (Float[].class.isAssignableFrom(clazz)) {
				Float[] args = new Float[vs.length];
				for (int i = 0; i < vs.length; i++) {
					if ("".equals(vs[i].trim()))
						vs[i] = "0.0";
					try {
						args[i] = Float.parseFloat(vs[i]);
					} catch (Exception e) {
						args[i] = 0.0F;
					}
				}
				return args;
			} else if (float[].class.isAssignableFrom(clazz)) {
				float[] args = new float[vs.length];
				for (int i = 0; i < vs.length; i++) {
					if ("".equals(vs[i].trim()))
						vs[i] = "0.0";
					try {
						args[i] = Float.parseFloat(vs[i]);
					} catch (Exception e) {
						args[i] = 0.0F;
					}
				}
				return args;
			} else if (Boolean[].class.isAssignableFrom(clazz)) {
				Boolean[] args = new Boolean[vs.length];
				for (int i = 0; i < vs.length; i++) {
					if ("".equals(vs[i].trim()))
						vs[i] = "false";
					try {
						args[i] = Boolean.parseBoolean(vs[i]);
					} catch (Exception e) {
						args[i] = false;
					}
				}
				return args;
			} else if (boolean[].class.isAssignableFrom(clazz)) {
				boolean[] args = new boolean[vs.length];
				for (int i = 0; i < vs.length; i++) {
					if ("".equals(vs[i].trim()))
						vs[i] = "false";
					try {
						args[i] = Boolean.parseBoolean(vs[i]);
					} catch (Exception e) {
						args[i] = false;
					}
				}
				return args;
			} else if (String[].class.isAssignableFrom(clazz)) {
				return vs;
			}
		} catch (Exception e) {
			return null;
		} catch (Error e) {
			return null;
		}
		return null;
	}

	public static Class<?> getGenericType(Field f) {
		Class<?> cls = f.getType();
		if (!Collection.class.isAssignableFrom(cls))
			return cls;
		ParameterizedType pt = (ParameterizedType) f.getGenericType();
		Type type = pt.getActualTypeArguments()[0];
		Class<?> targetCls = ClassUtil.getPojoClass(type.toString()
				.replace("class ", "").replace("interface ", "").trim());
		if (targetCls == null)
			return cls;
		return targetCls;
	}

	public static boolean isListClass(Field f) {
		Class<?> cls = f.getType();
		if (!Collection.class.isAssignableFrom(cls))
			return false;
		ParameterizedType pt = (ParameterizedType) f.getGenericType();
		Type type = pt.getActualTypeArguments()[0];
		Class<?> targetCls = ClassUtil.getPojoClass(type.toString().replace(
				"class ", ""));
		if (targetCls == null)
			return false;
		return true;
	}

	public static boolean isListString(Field f) {
		Class<?> cls = f.getType();
		if (!Collection.class.isAssignableFrom(cls))
			return false;
		ParameterizedType pt = (ParameterizedType) f.getGenericType();
		Type type = pt.getActualTypeArguments()[0];
		if ("class java.lang.String".equals(type.toString()))
			return true;
		return false;
	}

}
